home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 1843 / 1843.xpi / content / firebug / insideOutBox.js < prev    next >
Text File  |  2010-01-15  |  15KB  |  508 lines

  1. /* See license.txt for terms of usage */
  2.  
  3. FBL.ns(function() { with (FBL) {
  4.  
  5. /**
  6.  * View interface used to populate an InsideOutBox object.
  7.  *
  8.  * All views must implement this interface (directly or via duck typing).
  9.  */
  10. top.InsideOutBoxView = {
  11.     /**
  12.      * Retrieves the parent object for a given child object.
  13.      */
  14.     getParentObject: function(child) {},
  15.  
  16.     /**
  17.      * Retrieves a given child node.
  18.      *
  19.      * If both index and previousSibling are passed, the implementation
  20.      * may assume that previousSibling will be the return for getChildObject
  21.      * with index-1.
  22.      */
  23.     getChildObject: function(parent, index, previousSibling) {},
  24.  
  25.     /**
  26.      * Renders the HTML representation of the object. Should return an HTML
  27.      * object which will be displayed to the user.
  28.      */
  29.     createObjectBox: function(object, isRoot) {}
  30. };
  31.  
  32. /**
  33.  * Creates a tree based on objects provided by a separate "view" object.
  34.  *
  35.  * Construction uses an "inside-out" algorithm, meaning that the view's job is first
  36.  * to tell us the ancestry of each object, and secondarily its descendants.
  37.  */
  38. top.InsideOutBox = function(view, box)
  39. {
  40.     this.view = view;
  41.     this.box = box;
  42.  
  43.     this.rootObject = null;
  44.  
  45.     this.rootObjectBox = null;
  46.     this.selectedObjectBox = null;
  47.     this.highlightedObjectBox = null;
  48.  
  49.     this.onMouseDown = bind(this.onMouseDown, this);
  50.     box.addEventListener("mousedown", this.onMouseDown, false);
  51. };
  52.  
  53. InsideOutBox.prototype =
  54. {
  55.     destroy: function()
  56.     {
  57.         this.box.removeEventListener("mousedown", this.onMouseDown, false);
  58.     },
  59.  
  60.     highlight: function(object)
  61.     {
  62.         var objectBox = this.createObjectBox(object);
  63.         this.highlightObjectBox(objectBox);
  64.         return objectBox;
  65.     },
  66.  
  67.     openObject: function(object)
  68.     {
  69.         var firstChild = this.view.getChildObject(object, 0);
  70.         if (firstChild)
  71.             object = firstChild;
  72.  
  73.         var objectBox = this.createObjectBox(object);
  74.         this.openObjectBox(objectBox);
  75.         return objectBox;
  76.     },
  77.  
  78.     openToObject: function(object)
  79.     {
  80.         var objectBox = this.createObjectBox(object);
  81.         this.openObjectBox(objectBox);
  82.         return objectBox;
  83.     },
  84.  
  85.     select: function(object, makeBoxVisible, forceOpen, noScrollIntoView)
  86.     {
  87.         var objectBox = this.createObjectBox(object);
  88.         this.selectObjectBox(objectBox, forceOpen);
  89.         if (makeBoxVisible)
  90.         {
  91.             this.openObjectBox(objectBox);
  92.             if (!noScrollIntoView)
  93.                 scrollIntoCenterView(objectBox);
  94.         }
  95.         return objectBox;
  96.     },
  97.  
  98.     expandObject: function(object)
  99.     {
  100.         var objectBox = this.createObjectBox(object);
  101.         if (objectBox)
  102.             this.expandObjectBox(objectBox);
  103.     },
  104.  
  105.     contractObject: function(object)
  106.     {
  107.         var objectBox = this.createObjectBox(object);
  108.         if (objectBox)
  109.             this.contractObjectBox(objectBox);
  110.     },
  111.  
  112.     highlightObjectBox: function(objectBox)
  113.     {
  114.         if (this.highlightedObjectBox)
  115.         {
  116.             removeClass(this.highlightedObjectBox, "highlighted");
  117.  
  118.             var highlightedBox = this.getParentObjectBox(this.highlightedObjectBox);
  119.             for (; highlightedBox; highlightedBox = this.getParentObjectBox(highlightedBox))
  120.                 removeClass(highlightedBox, "highlightOpen");
  121.         }
  122.  
  123.         this.highlightedObjectBox = objectBox;
  124.  
  125.         if (objectBox)
  126.         {
  127.             setClass(objectBox, "highlighted");
  128.  
  129.             var highlightedBox = this.getParentObjectBox(objectBox);
  130.             for (; highlightedBox; highlightedBox = this.getParentObjectBox(highlightedBox))
  131.                 setClass(highlightedBox, "highlightOpen");
  132.  
  133.            scrollIntoCenterView(objectBox);
  134.         }
  135.     },
  136.  
  137.     selectObjectBox: function(objectBox, forceOpen)
  138.     {
  139.         var isSelected = this.selectedObjectBox && objectBox == this.selectedObjectBox;
  140.         if (!isSelected)
  141.         {
  142.             removeClass(this.selectedObjectBox, "selected");
  143.             dispatch([Firebug.A11yModel], 'onObjectBoxUnselected', [this.selectedObjectBox]);
  144.             this.selectedObjectBox = objectBox;
  145.  
  146.             if (objectBox)
  147.             {
  148.                 setClass(objectBox, "selected");
  149.  
  150.                 // Force it open the first time it is selected
  151.                 if (forceOpen)
  152.                     this.toggleObjectBox(objectBox, true);
  153.             }
  154.         }
  155.         dispatch([Firebug.A11yModel], 'onObjectBoxSelected', [objectBox]);
  156.     },
  157.  
  158.     openObjectBox: function(objectBox)
  159.     {
  160.         if (objectBox)
  161.         {
  162.             // Set all of the node's ancestors to be permanently open
  163.             var parentBox = this.getParentObjectBox(objectBox);
  164.             var labelBox;
  165.             for (; parentBox; parentBox = this.getParentObjectBox(parentBox))
  166.             {
  167.                 setClass(parentBox, "open");
  168.                 labelBox = parentBox.getElementsByClassName('nodeLabelBox').item(0);
  169.                 if (labelBox)
  170.                     labelBox.setAttribute('aria-expanded', 'true')
  171.             }
  172.         }
  173.     },
  174.  
  175.     expandObjectBox: function(objectBox)
  176.     {
  177.         var nodeChildBox = this.getChildObjectBox(objectBox);
  178.         if (!nodeChildBox)
  179.             return;
  180.  
  181.         if (!objectBox.populated)
  182.         {
  183.             var firstChild = this.view.getChildObject(objectBox.repObject, 0);
  184.             this.populateChildBox(firstChild, nodeChildBox);
  185.         }
  186.         var labelBox = objectBox.getElementsByClassName('nodeLabelBox').item(0);
  187.         if (labelBox)
  188.             labelBox.setAttribute('aria-expanded', 'true');
  189.         setClass(objectBox, "open");
  190.     },
  191.  
  192.     contractObjectBox: function(objectBox)
  193.     {
  194.         removeClass(objectBox, "open");
  195.         var nodeLabel = objectBox.getElementsByClassName("nodeLabel").item(0);
  196.         var labelBox = nodeLabel.getElementsByClassName('nodeLabelBox').item(0);
  197.         if (labelBox)
  198.             labelBox.setAttribute('aria-expanded', 'false');
  199.     },
  200.  
  201.     toggleObjectBox: function(objectBox, forceOpen)
  202.     {
  203.         var isOpen = hasClass(objectBox, "open");
  204.         var nodeLabel = objectBox.getElementsByClassName("nodeLabel").item(0);
  205.         var labelBox = nodeLabel.getElementsByClassName('nodeLabelBox').item(0);
  206.         if (labelBox)
  207.             labelBox.setAttribute('aria-expanded', isOpen);
  208.         if (!forceOpen && isOpen)
  209.             this.contractObjectBox(objectBox);
  210.  
  211.         else if (!isOpen)
  212.             this.expandObjectBox(objectBox);
  213.     },
  214.  
  215.     getNextObjectBox: function(objectBox)
  216.     {
  217.         return findNext(objectBox, isVisibleTarget, false, this.box);
  218.     },
  219.  
  220.     getPreviousObjectBox: function(objectBox)
  221.     {
  222.         return findPrevious(objectBox, isVisibleTarget, true, this.box);
  223.     },
  224.  
  225.     /**
  226.      * Creates all of the boxes for an object, its ancestors, and siblings.
  227.      */
  228.     createObjectBox: function(object)
  229.     {
  230.         if (!object)
  231.             return null;
  232.  
  233.         this.rootObject = this.getRootNode(object);
  234.  
  235.         // Get or create all of the boxes for the target and its ancestors
  236.         var objectBox = this.createObjectBoxes(object, this.rootObject);
  237.  
  238.         if (!objectBox)
  239.             return null;
  240.         else if (object == this.rootObject)
  241.             return objectBox;
  242.         else
  243.             return this.populateChildBox(object, objectBox.parentNode);
  244.     },
  245.  
  246.     /**
  247.      * Creates all of the boxes for an object, its ancestors, and siblings up to a root.
  248.      */
  249.     createObjectBoxes: function(object, rootObject)
  250.     {
  251.         if (!object)
  252.             return null;
  253.  
  254.         if (object == rootObject)
  255.         {
  256.             if (!this.rootObjectBox || this.rootObjectBox.repObject != rootObject)
  257.             {
  258.                 if (this.rootObjectBox)
  259.                 {
  260.                     try {
  261.                         this.box.removeChild(this.rootObjectBox);
  262.                     } catch (exc) {
  263.                     }
  264.                 }
  265.  
  266.                 this.highlightedObjectBox = null;
  267.                 this.selectedObjectBox = null;
  268.                 this.rootObjectBox = this.view.createObjectBox(object, true);
  269.                 this.box.appendChild(this.rootObjectBox);
  270.             }
  271.             return this.rootObjectBox;
  272.         }
  273.         else
  274.         {
  275.             var parentNode = this.view.getParentObject(object);
  276.  
  277.             var parentObjectBox = this.createObjectBoxes(parentNode, rootObject);
  278.             if (!parentObjectBox)
  279.                 return null;
  280.  
  281.             var parentChildBox = this.getChildObjectBox(parentObjectBox);
  282.             if (!parentChildBox)
  283.                 return null;
  284.  
  285.             var childObjectBox = this.findChildObjectBox(parentChildBox, object);
  286.             return childObjectBox
  287.                 ? childObjectBox
  288.                 : this.populateChildBox(object, parentChildBox);
  289.         }
  290.     },
  291.  
  292.     findObjectBox: function(object)
  293.     {
  294.         if (!object)
  295.             return null;
  296.  
  297.         if (object == this.rootObject)
  298.             return this.rootObjectBox;
  299.         else
  300.         {
  301.             var parentNode = this.view.getParentObject(object);
  302.             var parentObjectBox = this.findObjectBox(parentNode);
  303.             if (!parentObjectBox)
  304.                 return null;
  305.  
  306.             var parentChildBox = this.getChildObjectBox(parentObjectBox);
  307.             if (!parentChildBox)
  308.                 return null;
  309.  
  310.             return this.findChildObjectBox(parentChildBox, object);
  311.         }
  312.     },
  313.  
  314.     appendChildBox: function(parentNodeBox, repObject)
  315.     {
  316.         var childBox = this.getChildObjectBox(parentNodeBox);
  317.         var objectBox = this.findChildObjectBox(childBox, repObject);
  318.         if (objectBox)
  319.             return objectBox;
  320.  
  321.         objectBox = this.view.createObjectBox(repObject);
  322.         if (objectBox)
  323.         {
  324.             var childBox = this.getChildObjectBox(parentNodeBox);
  325.             childBox.appendChild(objectBox);
  326.         }
  327.         return objectBox;
  328.     },
  329.  
  330.     insertChildBoxBefore: function(parentNodeBox, repObject, nextSibling)
  331.     {
  332.         var childBox = this.getChildObjectBox(parentNodeBox);
  333.         var objectBox = this.findChildObjectBox(childBox, repObject);
  334.         if (objectBox)
  335.             return objectBox;
  336.  
  337.         objectBox = this.view.createObjectBox(repObject);
  338.         if (objectBox)
  339.         {
  340.             var siblingBox = this.findChildObjectBox(childBox, nextSibling);
  341.             childBox.insertBefore(objectBox, siblingBox);
  342.         }
  343.         return objectBox;
  344.     },
  345.  
  346.     removeChildBox: function(parentNodeBox, repObject)
  347.     {
  348.         var childBox = this.getChildObjectBox(parentNodeBox);
  349.         var objectBox = this.findChildObjectBox(childBox, repObject);
  350.         if (objectBox)
  351.             childBox.removeChild(objectBox);
  352.     },
  353.  
  354.     populateChildBox: function(repObject, nodeChildBox)  // We want all children of the parent of repObject.
  355.     {
  356.         if (!repObject)
  357.             return null;
  358.  
  359.         var parentObjectBox = getAncestorByClass(nodeChildBox, "nodeBox");
  360.         if (parentObjectBox.populated)
  361.             return this.findChildObjectBox(nodeChildBox, repObject);
  362.  
  363.         var lastSiblingBox = this.getChildObjectBox(nodeChildBox);
  364.         var siblingBox = nodeChildBox.firstChild;
  365.         var targetBox = null;
  366.  
  367.         var view = this.view;
  368.  
  369.         var targetSibling = null;
  370.         var parentNode = view.getParentObject(repObject);
  371.         for (var i = 0; 1; ++i)
  372.         {
  373.             targetSibling = view.getChildObject(parentNode, i, targetSibling);
  374.             if (!targetSibling)
  375.                 break;
  376.  
  377.             // Check if we need to start appending, or continue to insert before
  378.             if (lastSiblingBox && lastSiblingBox.repObject == targetSibling)
  379.                 lastSiblingBox = null;
  380.  
  381.             if (!siblingBox || siblingBox.repObject != targetSibling)
  382.             {
  383.                 var newBox = view.createObjectBox(targetSibling);
  384.                 if (newBox)
  385.                 {
  386.                     if (lastSiblingBox)
  387.                         nodeChildBox.insertBefore(newBox, lastSiblingBox);
  388.                     else
  389.                         nodeChildBox.appendChild(newBox);
  390.                 }
  391.  
  392.                 siblingBox = newBox;
  393.             }
  394.  
  395.             if (targetSibling == repObject)
  396.                 targetBox = siblingBox;
  397.  
  398.             if (siblingBox && siblingBox.repObject == targetSibling)
  399.                 siblingBox = siblingBox.nextSibling;
  400.         }
  401.  
  402.         if (targetBox)
  403.             parentObjectBox.populated = true;
  404.         return targetBox;
  405.     },
  406.  
  407.     getParentObjectBox: function(objectBox)
  408.     {
  409.         var parent = objectBox.parentNode ? objectBox.parentNode.parentNode : null;
  410.         return parent && parent.repObject ? parent : null;
  411.     },
  412.  
  413.     getChildObjectBox: function(objectBox)
  414.     {
  415.         return objectBox.getElementsByClassName("nodeChildBox").item(0);
  416.     },
  417.  
  418.     findChildObjectBox: function(parentNodeBox, repObject)
  419.     {
  420.         for (var childBox = parentNodeBox.firstChild; childBox; childBox = childBox.nextSibling)
  421.         {
  422.             if (childBox.repObject == repObject)
  423.                 return childBox;
  424.         }
  425.     },
  426.  
  427.     /**
  428.      * Determines if the given node is an ancestor of the current root.
  429.      */
  430.     isInExistingRoot: function(node)
  431.     {
  432.         var parentNode = node;
  433.         while (parentNode && parentNode != this.rootObject)
  434.         {
  435.             var parentNode = this.view.getParentObject(parentNode);
  436.         }
  437.         return parentNode == this.rootObject;
  438.     },
  439.  
  440.     getRootNode: function(node)
  441.     {
  442.         while (1)
  443.         {
  444.             var parentNode = this.view.getParentObject(node);
  445.             if (!parentNode)
  446.                 return node;
  447.             else
  448.                 node = parentNode;
  449.         }
  450.         return null;
  451.     },
  452.  
  453.     // ********************************************************************************************
  454.  
  455.     onMouseDown: function(event)
  456.     {
  457.         var hitTwisty = false;
  458.         for (var child = event.target; child; child = child.parentNode)
  459.         {
  460.             if (hasClass(child, "twisty"))
  461.                 hitTwisty = true;
  462.             else if (child.repObject)
  463.             {
  464.                 if (hitTwisty)
  465.                     this.toggleObjectBox(child);
  466.                 break;
  467.             }
  468.         }
  469.     }
  470. };
  471.  
  472. // ************************************************************************************************
  473. // Local Helpers
  474.  
  475. function isVisibleTarget(node)
  476. {
  477.     if (node.repObject && node.repObject.nodeType == Node.ELEMENT_NODE)
  478.     {
  479.         for (var parent = node.parentNode; parent; parent = parent.parentNode)
  480.         {
  481.             if (hasClass(parent, "nodeChildBox")
  482.                 && !hasClass(parent.parentNode, "open")
  483.                 && !hasClass(parent.parentNode, "highlightOpen"))
  484.                 return false;
  485.         }
  486.         return true;
  487.     }
  488. }
  489.  
  490. function formatNode(object)
  491. {
  492.     if (object)
  493.         return (object.localName ? object.localName : object);
  494.     else
  495.         return "(null object)";
  496. }
  497.  
  498. function getObjectPath(element, aView)
  499. {
  500.     var path = [];
  501.     for (; element; element = aView.getParentObject(element))
  502.         path.push(element);
  503.  
  504.     return path;
  505. }
  506.  
  507. }});
  508.